#include "page_allocator.h"
#include "../container/LinkList.h"
#include "../sync/lock.h"
#include "../time/time.h"
#include <stdint.h>
#include <set>
#include <thread>
#include <functional>
#include <chrono>
#include <vector>

#ifndef BASSERT
#define BASSERT //TODO 
#endif // !BASSERT

namespace qb{
	namespace base{
		class MemoryPage{
		public:
			enum{
				kPageGuard = 0xFE21FD31,		// MemoryPage的守卫值,前后都有
				kPageBits = 16,				// 
				kPageSize = 1 << kPageBits,	// 每次分配内存尺寸的单位,以此整数倍来分配
			};
		protected:
			typedef unsigned char byte;
			MemoryPage*	m_next;			// 双链表的下一个
			MemoryPage*	m_prev;			// 双链表的的上一个
			uint32_t	m_guard;		// 守卫值
			uint32_t	m_tick;			// 创建后的时间
			int			m_capcity;		// 当前页面的m_buffer总大小
			int			m_offset;		// 下一次分配的偏移量
			int			m_count;		// 已经分配了多少个
			byte*		m_buffer;		// 指向紧跟当前类后面的内存
		private:
			MemoryPage() = delete;		// 此类不准创建
			~MemoryPage() = delete;		// 此类不准创建
		public:
			static int GetStaticSize(){ return sizeof(MemoryPage) + sizeof(uint32_t); }
			static bool CheckPage(const MemoryPage* page)
			{
				if (page == nullptr)
					return false;
				if (page->GetNext() != nullptr || page->GetPrev() != nullptr)
					return false;
				if (page->m_guard != kPageGuard)
					return false;
				const byte* buf = (const byte*)page + sizeof(MemoryPage);
				if (page->m_buffer != buf)
					return false;
				if (*((uint32_t*)(buf + page->m_capcity)) != kPageGuard)
					return false;
				if (page->m_offset<0 || page->m_offset>page->m_capcity)
					return false;
				int size = MemoryPage::GetStaticSize() + page->m_capcity;
				if (size % MemoryPage::kPageSize != 0)
					return false;
				return true;
			}
			void Build(void* buffer, int size)
			{
				// 最开头和最末位都必须设定一个固定值
				BASSERT(buffer && size > 0 && size % MemoryPage::kPageSize == 0);
				m_prev = nullptr;
				m_next = nullptr;
				m_guard = kPageGuard;
				m_tick = GetTickCount();
				m_capcity = size - MemoryPage::GetStaticSize();
				m_offset = 0;
				m_count = 0;
				m_buffer = (byte*)buffer + sizeof(MemoryPage);
				//memset(m_buffer, 0, m_capcity);
				m_buffer[0] = '\0';//不做全部零初始化,开销大
				byte* pend = &((byte*)buffer)[size - sizeof(uint32_t)];
				*((uint32_t*)pend) = kPageGuard;
			}
			void SetNext(MemoryPage* next){ BASSERT(next != this); m_next = next; }
			void SetPrev(MemoryPage* prev){ BASSERT(prev != this); m_prev = prev; }
			MemoryPage* GetNext()const{ return m_next; }
			MemoryPage* GetPrev()const{ return m_prev; }
			int CountList()const{
				int ncout = 0;
				const MemoryPage* cur = this;
				while (cur)
				{
					ncout++;
					cur = cur->GetNext();
				}
				return ncout;
			}
			MemoryPage* Link(MemoryPage* page)
			{
				//将page连接到当前后面
				BASSERT(page != nullptr && page->GetNext() == nullptr && page->GetPrev() == nullptr);
				page->SetNext(m_next);
				page->SetPrev(this);
				if (m_next)m_next->SetPrev(page);
				m_next = page;
				return this;
			}
			MemoryPage* LinkBySpace(MemoryPage* page, int maxStep)
			{
				// 将page插入到当前双链表中,按照space递减排列,最多找maxStep次
				// 注意,不是严格递减,考虑到性能
				// 如果插入到开头,返回page,否则返回page之前的
				BASSERT(page != nullptr && page->GetNext() == nullptr && page->GetPrev() == nullptr);
				int space = page->GetSpace();
				if (space >= GetSpace())
				{
					// 大于当前的空余空间,已经在外面添加
					return nullptr;
				}
				MemoryPage* prev = this;
				MemoryPage* cur = GetNext();
				int i = 0;
				for (; i < maxStep; i++)
				{
					if (cur == nullptr || space >= cur->GetSpace())
					{
						prev->Link(page);
						return prev;
					}
					prev = cur;
					cur = cur->GetNext();
				}
				prev->Link(page);
				return prev;
			}
			MemoryPage* Unlink()
			{
				// 从双链表中断开
				MemoryPage* prev = m_prev;
				if (m_prev)
					m_prev->SetNext(m_next);
				if (m_next)
					m_next->SetPrev(m_prev);
				m_next = nullptr;
				m_prev = nullptr;
				return prev;
			}

			void Reset(){
				BASSERT(m_buffer && GetTotalBytes() % kPageSize == 0);
				//memset(m_buffer, 0, m_capcity);
				m_buffer[0] = '\0';//较大范围的不必要的memset是性能瓶颈,保留脏数据,后续分配的时候清除
				m_guard = kPageGuard;
				//m_tick = GetTickCount();
				m_offset = 0;
				m_count = 0;
				byte* pend = &((byte*)m_buffer)[m_capcity];
				*((uint32_t*)pend) = kPageGuard;
			}
			inline void SetTick(uint32_t tick){ m_tick = tick; }
			inline uint32_t GetTick()const{ return m_tick; }
			inline int GetTotalBytes()const{ return m_capcity + MemoryPage::GetStaticSize(); }
			inline int GetCapcity()const{ return m_capcity; }
			inline int GetSpace()const{ return m_capcity - m_offset; }
			void* Alloc(int bytes, int align = 4)
			{
				int offset = m_offset;
				if (offset%align != 0)
					offset = ((offset / align) + 1)*align;
				if (offset + bytes > m_capcity)
					return nullptr;
				void* ptr = m_buffer + offset;
				//memset(ptr, 0, bytes);//为了性能,不初始化为0,外部有构造函数都会进一步初始化
				m_offset = offset + bytes;
				m_count++;
				return ptr;
			}
		};

		class CentralAllocator{			// 全局中央分配器
			enum{
				kMegaSize = 1024 * 1024,
				kMegaBits = 20,			// 1mb的比特位数
				kSlotCount = 256,		// 中央内存堆中哈希表的尺寸,不宜过大
				kCacheGB = 1024,		// 1024mb
				kCacheMax = 256,		// 当缓存多余此值时,释放页面时,立即释放给系统而不是放入缓存
				kCacheCheck = 128,		// 当缓存多余此值时,触发自动清除检查
				kCacheMin = 64,			// 当缓存低于此值时,终止之前触发的自动清除检查
				kCacheLife = 1 * 60 * 1000,	// 一个缓存的最大生命周期,1分钟,超过此值在检查阶段可能被删除
				kCheckInterval = 1000,	// 检查阶段,每间隔多少毫秒钟检测一次
				kShortLife = 4000,		// 小于此值的算短生命周期,其页面释放优先进入缓存
				kMaxShortCount = 1024,	// 短生命周期的页面个数
				kCheckMaxTime = 20,		// 每次最多检查多少毫秒	
				kRemoveTimes = 20		// 每次最多删除多少个
			};
			static_assert(kCacheMin < kCacheCheck, "kCacheMin must be smaller than kCacheCheck");
			static_assert(kCacheCheck < kCacheMax, "kCacheCheck must be smaller than kCacheMax");
			// 全局中央分配器,多个线程同步

			typedef std::set<MemoryPage*>	MemoryPageSet;
			typedef std::set<PageAllocator*>	AllocatorSet;
		protected:
			CSLock		m_lock;
			DoubleLinkList<MemoryPage>	m_slots[kSlotCount];	// <=1mb的双链表,位于某个index的MemoryPage,其尺寸
			// 是kPageSize的(index+1)倍
			// 最末尾的尺寸为kPageSize*kSlotCount,最大4mb
			int64_t			m_allocated_bytes;	// 已经分配的,供外部使用的所有内存总数
			int64_t			m_cached_bytes;		// 留在m_slots中缓存的所有内存总数
			uint32_t		m_lasttick;			// 上一次检查的时间
			int				m_lastslot;			// 上一次检查的插槽,每次检查都沿着上一次检查的位置进行下去
			int64_t			m_deepcopy_count;	// 深度拷贝的总次数
			double			m_deepcopy_time;	// 深度拷贝的总时间
			MemoryPageSet*	m_allocated;		// 已经分配的共外部使用的页面集合,用于调试
			AllocatorSet	m_allocators;		// 所有的Allocator;
			uint32_t		m_last_time;		// 上一次
			std::thread*	m_thread;
			bool			m_track_allocators;	// 
			bool			m_check_dirty;		// 当全部检查完毕,不需要反复扫描检查;只要缓存中有新增,立刻为true;
			bool			m_exit = false;
		private:
			CentralAllocator() :m_allocated_bytes(0), m_cached_bytes(0), m_lastslot(0), m_lasttick(0),
				m_allocated(nullptr), m_track_allocators(false), m_last_time(0),
				m_deepcopy_count(0), m_deepcopy_time(0), m_check_dirty(false)
			{
				m_thread = new std::thread(std::bind(&CentralAllocator::runCheck, this));
			}
			static void runCheck(CentralAllocator* ca)
			{
				int64_t wait_time = 1000;
				try {
					while (true)
					{
						if (ca->m_exit)
							return;
						std::this_thread::sleep_for(std::chrono::milliseconds(wait_time));
						wait_time = ca->CheckPageDynamicly() ? 1000 : 20;
						std::this_thread::yield();
					}
				}catch(...){}
			}
			~CentralAllocator()
			{
				m_exit = true;
				m_thread->join();
				ScopedLock<CSLock> _scoped(m_lock);// 同步
				for (int i = 0; i < kSlotCount; i++)
				{
					while (MemoryPage* cur = m_slots[i].PickHead())
					{
						FreeMemory(cur);
					}
				}
			}
			int64_t GetCachedBytes(){
				ScopedLock<CSLock> _scoped(m_lock);
				return m_cached_bytes;
			}

		public:
			bool CheckPageDynamicly()
			{
				/*
				当m_cached_bytes 越大越偏离kCacheCheck,释放的越快
				当m_cached_bytes 越靠近kCacheCheck, 释放的越慢
				限制每一次调用的作用时间不超过kCheckMaxTime
				设定3个节点:其他的按照线性插值
				kCacheCheck		1
				kCacheMax		30mb
				1gb				100mb
				*/
				static_assert(kCacheMax > kCacheCheck && kCacheGB > kCacheMax, "kCacheMax > kCacheCheck && kCacheGB > kCacheMax failed");
				const double check_bytes = 1;
				const double max_bytes = 30;
				const double gb_bytes = 100;
				int64_t cache = GetCachedBytes() >> kMegaBits;
				double mgbytes = check_bytes;
				if (cache <= kCacheCheck)
					return true;

				if (cache < kCacheMax)
					mgbytes = 1.0*(cache - kCacheCheck)*(max_bytes - check_bytes) / (kCacheMax - kCacheCheck) + check_bytes;
				else if (cache < kCacheGB)
					mgbytes = 1.0*(cache - kCacheMax)*(gb_bytes - max_bytes) / (kCacheGB - kCacheMax) + max_bytes;
				else mgbytes = gb_bytes;
				mgbytes = mgbytes*kMegaSize;

				// 找到最老的一个插槽
				uint32_t tick = GetTickCount();
				if (m_exit)
					return true;

				int sum_bytes = 0;
				int check_count = 0;
				while (true)
				{
					int bytes = CheckOldestPage();
					if (bytes <= 0)
						break;
					sum_bytes += bytes;
					check_count++;
					if (sum_bytes > mgbytes || GetTickCount() - tick>kCheckMaxTime)
						break;
				}
				if (cache <= kCacheCheck || sum_bytes >= mgbytes)
					return true;
				return false;
			}
			int CheckOldestPage()
			{
				int index = -1;
				int bytes = 0;
				uint32_t tick = 0;
				MemoryPage* page = nullptr;
				{
					ScopedLock<CSLock> _scoped(m_lock);
					for (int i = 0; i < kSlotCount; i++)
					{
						DoubleLinkList<MemoryPage>& pinfo = m_slots[i];
						MemoryPage* temp = pinfo.GetTail();
						if (temp == nullptr)
							continue;
						if (index >= 0 && temp->GetTick() >= tick)
							continue;
						tick = (index < 0 || temp->GetTick()< tick) ? temp->GetTick() : tick;
						index = i;
					}
					if (index >= 0)
					{
						DoubleLinkList<MemoryPage>& pinfo = m_slots[index];
						if (pinfo.GetTail())
						{
							page = pinfo.PickTail();
							bytes = page->GetTotalBytes();
							m_cached_bytes -= bytes;
						}
					}
				}

				// 将FreeMemory放在锁外面,缩短锁的时间
				if (page)
					FreeMemory(page);
				return bytes;
			}
			static CentralAllocator& Get(){
				static CentralAllocator central_allocator;
				return central_allocator;
			}
			PageAllocator* CreateAllocator(const PageAllocator::RootPtrType root, bool inMessage);
			void DestroyAllocator(PageAllocator* allocator);

			MemoryPage* AllocPage(int bytes)
			{
				int pagewasted = MemoryPage::GetStaticSize();//末尾Guard
				int index = ((bytes + pagewasted) >> MemoryPage::kPageBits);
				MemoryPage* page = nullptr;
				if (index < kSlotCount)
				{
					ScopedLock<CSLock> _scoped(m_lock);// 同步
					for (int i = 0; i < 2 && index + i<kSlotCount; i++)
					{
						int slot = index + i;
						DoubleLinkList<MemoryPage>& pi = m_slots[slot];
						if (pi.GetHead() && pi.GetHead()->GetCapcity() >= bytes)
						{
							page = pi.PickHead();
							page->Reset();
							m_cached_bytes -= page->GetTotalBytes();
							m_allocated_bytes += page->GetTotalBytes();
							break;
						}
					}
					if (page && m_allocated)
						m_allocated->insert(page);
				}

				bool allocnew = false;
				if (page == nullptr)
				{
					allocnew = true;
					int size = (index + 1)*MemoryPage::kPageSize;
					char* buf = (char*)MallocMemory(size);
					page = (MemoryPage*)buf;
					page->Build(buf, size);
					page->SetNext(nullptr);
					page->SetPrev(nullptr);
					{
						ScopedLock<CSLock> _scoped(m_lock);
						m_allocated_bytes += page->GetTotalBytes();
						if (page && m_allocated)
							m_allocated->insert(page);
					}
				}
				BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);

				// 当缓存池大小
				if (allocnew || (m_cached_bytes >> kMegaBits) >= kCacheCheck)
				{
					CheckOldPage();
				}
				return page;
			}
			void FreePage(MemoryPage* page,bool force=false)
			{
				if (page == nullptr)
					return;
				BASSERT(page->GetNext() == nullptr && page->GetPrev() == nullptr);
				BASSERT(page->GetTotalBytes() % MemoryPage::kPageSize == 0);
				int slot = page->GetTotalBytes() >> MemoryPage::kPageBits;
				uint32_t tick = GetTickCount();
				ScopedLock<CSLock> _scoped(m_lock);
				m_allocated_bytes -= page->GetTotalBytes();
				if (m_allocated)
				{
					MemoryPageSet::iterator it = m_allocated->find(page);
					if (it != m_allocated->end())
						m_allocated->erase(it);
				}

				// 当page为1个单位且是最近分配的时候,通常是栈上Message临时分配使用
				// 这样的Message会在栈上频繁反复的构造,导致此种情况非常频繁,需要特殊优化
				if (force)
				{
					BASSERT(MemoryPage::CheckPage(page));
					FreeMemory(page);
				}
				else if ((slot == 1 && tick - page->GetTick() < kShortLife && m_slots[slot].GetCount() <= kMaxShortCount) ||
					slot < kSlotCount ||
					(m_cached_bytes >> kMegaBits) < kCacheMax)
				{
					page->Reset();
					m_slots[slot].InsertHead(page);
					BASSERT(m_slots[slot].GetHead() == page && page->GetPrev() == nullptr);
					m_cached_bytes += page->GetTotalBytes();
					m_check_dirty = true;
				}
				else
				{
					BASSERT(MemoryPage::CheckPage(page));
					FreeMemory(page);
				}
			}
			void CheckOldPage()
			{
				// 间隔删除长时间不用的缓存页面
				uint32_t tick = GetTickCount();
				MemoryPage* head = nullptr;
				//if (tick > m_lasttick + kCheckInterval)
				{
					ScopedLock<CSLock> _scoped(m_lock);
					//m_lasttick = tick;
					int nremoved = 0;
					for (int i = 0; i < kSlotCount; i++)
					{
						m_lastslot = (m_lastslot + 1) % kSlotCount;
						DoubleLinkList<MemoryPage>& pinfo = m_slots[m_lastslot];
						MemoryPage* page = pinfo.GetTail();
						if (page && tick > page->GetTick() + kCacheLife)
						{
							page = pinfo.PickTail();
							m_cached_bytes -= page->GetTotalBytes();
							if (head == nullptr)
								head = page;
							else
								head->Link(page);
							nremoved++;
						}
						if (nremoved >= kRemoveTimes ||
							GetTickCount() > tick + kCheckMaxTime ||
							(m_cached_bytes >> kMegaBits) < kCacheMin)
							break;
					}
				}
				while (head)
				{
					MemoryPage* next = head->GetNext();
					FreeMemory(head);
					head = next;
				}
			}
			void AddDeepCopyCount(double time)
			{
				if (!m_track_allocators)
					return;
				ScopedLock<CSLock> _scoped(m_lock);
				m_deepcopy_count++;
				m_deepcopy_time += time;
			}
		protected:
			void TrackAllocator(PageAllocator* allocator, bool add);
			int GetTotalCount()const{
				int ntotal = 0;
				for (int i = 0; i < kSlotCount; i++)
				{
					ntotal += m_slots[i].GetCount();
				}
				return ntotal;
			}
			void DumpStatus()
			{
				int ntotal = GetTotalCount();
				int nactive = m_allocated ? (int)m_allocated->size() : 0;
				//char buf[1024] = { 0 };
				//BVIEW("[SDBUS][CentralAllocator]cached:%I64d allocated:%I64d  total:%I64d  count:%6d active:%6d", m_cached_bytes,
				//	m_allocated_bytes, m_totalbytes, GetTotalCount(), nactive);
			}
			void* MallocMemory(int bytes)
			{
				return ::malloc(bytes);
			}
			void FreeMemory(MemoryPage* page)
			{
				if (page)
				{
					::free((char*)page);
				}
			}
		};

		class MemoryPageList{
			enum {
				kSpaceGap = 128,			// 空余空间按照此数值来分组到若干个双链表中
				kSpaceSlot = 32,			// 总共有多少个空余的双链表
				kSpaceMin = 16,			// 当MemoryPage末尾空余小于16字节,忽略,放入m_full中,值越大,浪费越多,性能越好
				kMaxLinkStep = 64			// 最大连接次数,值越大,LinkBySpace耗时越长,效果越好
			};
			static_assert(kSpaceSlot == sizeof(unsigned int) * 8, "kSpaceSlot must be sizeof(unsingned int)");
			DoubleLinkList<MemoryPage>		m_head[kSpaceSlot];	// 有空闲内存空间的双链表
			// 索引值越大,空闲空间越多
			// index*kSpaceGap<=空闲空间<(index+1)*kSpaceGap
			MemoryPage*		m_full;				// 已经满的双链表
			int				m_full_count;		// 已经满的双链表里的MemoryPage个数
			int				m_total_bytes;		// 总体累积内存
			int				m_total_count;
			bool			m_force_free;
		public:
			MemoryPageList(bool force) :m_full(nullptr), m_full_count(0), m_total_bytes(0), m_total_count(0),
				m_force_free(force){
			}
			~MemoryPageList()
			{
				Release();
			}
			int GetBytes()const{ return m_total_bytes; }
			void AddPage(MemoryPage* page)
			{
				// 待加入的page必须是孤立的MemoryPage
				BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);
				AddPageImpl(page);
				m_total_bytes += page->GetTotalBytes();
				m_total_count++;
			}
			void* Alloc(int bytes)
			{
				int slot = bytes / kSpaceGap;
				slot = slot >= kSpaceSlot ? (kSpaceSlot - 1) : slot;
				for (int i = slot; i < kSpaceSlot; i++)
				{
					MemoryPage* head = m_head[i].GetHead();
					void* ptr = head ? head->Alloc(bytes) : nullptr;
					if (ptr)
					{
						BASSERT(head && head->GetPrev() == nullptr);
						head = m_head[i].PickHead();
						AddPageImpl(head);
						return ptr;
					}
				}
				return nullptr;
			}
			int Release()
			{
				int ncount = ReleaseList(m_full);
				m_full = nullptr;
				m_full_count = 0;
				for (int i = 0; i < kSpaceSlot; i++)
				{
					DoubleLinkList<MemoryPage>& mslot = m_head[i];
					int count = mslot.GetCount();
					while (MemoryPage* head = mslot.PickHead())
					{
						CentralAllocator::Get().FreePage(head,m_force_free);
					}
					ncount += count;
				}
				BASSERT(ncount == m_total_count);
				m_total_count = 0;
				return ncount;
			}
		protected:
			void CheckAll()
			{
				return;
				std::vector<MemoryPage*> pages;
				int ncount = m_full ? m_full->CountList() : 0;
				for (int i = 0; i < kSpaceSlot; i++)
				{
					DoubleLinkList<MemoryPage>& mslot = m_head[i];
					int acount = mslot.GetCount();
					MemoryPage* head = mslot.GetHead();
					if (head)
					{
						pages.clear();
						pages.reserve(acount);
						for (int k = 0; k < acount; k++)
						{
							if (head)pages.push_back(head);
							BASSERT(head);
							head = head->GetNext();
						}
					}
					ncount += acount;
				}
				//BASSERT(ncount == m_total_count);
			}
			void AddPageImpl(MemoryPage* page)
			{
				BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);
				int space = page->GetSpace();
				if (space <= kSpaceMin)
				{
					if (m_full)
						m_full->Link(page);
					else
						m_full = page;
					m_full_count++;
				}
				else
				{
					// 如果空闲空间非常多,将其加到最末一个双链表开头
					// 将page按照其空闲空间的多少放到合适的双链表中
					int slot = space / kSpaceGap;
					if (slot >= kSpaceSlot)
						slot = kSpaceSlot - 1;
					DoubleLinkList<MemoryPage>& mslot = m_head[slot];
					mslot.InsertBySpace(page, kMaxLinkStep);
				}
			}
			int ReleaseList(MemoryPage* head)
			{
				int ncount = 0;
				while (head)
				{
					MemoryPage* cur = head;
					head = head->GetNext();
					cur->SetNext(nullptr);
					cur->SetPrev(nullptr);
					CentralAllocator::Get().FreePage(cur, m_force_free);
					ncount++;
				}
				return ncount;
			}
		};

		/////////////////////////////////////////////////////////////////////////////
		PageAllocator* CentralAllocator::CreateAllocator(const PageAllocator::RootPtrType root, bool inMessage){

			PageAllocator* a = new PageAllocator(root, inMessage);
			if (m_track_allocators && inMessage)
				TrackAllocator(a, true);
			return a;
		}
		void CentralAllocator::DestroyAllocator(PageAllocator* allocator)
		{
			if (allocator)
			{
				if (m_track_allocators)
					TrackAllocator(allocator, false);
				delete allocator;
			}
		}
		void CentralAllocator::TrackAllocator(PageAllocator* allocator, bool add)
		{
			if (allocator == nullptr)
				return;
			ScopedLock<CSLock> _scoped(m_lock);
			if (add)
			{
				AllocatorSet::iterator it = m_allocators.find(allocator);
				if (it != m_allocators.end())
				{
					//BVIEW("[SDBUS]Allocator:0x%8x already exist", allocator);
				}
				m_allocators.insert(allocator);
			}
			else
			{
				AllocatorSet::iterator it = m_allocators.find(allocator);
				if (it == m_allocators.end())
				{
					//if (allocator->IsInMessage())
						//BVIEW("[SDBUS]Allocator:0x%8x does not exist", allocator);
				}
				else
					m_allocators.erase(it);
			}
			uint32_t tick = GetTickCount();
			if (tick > m_last_time + 5000)
			{
				m_last_time = tick;
				/*
				BVIEW("[SDBUS]pid:%8d current messages:%6d total bytes:%I64d = %6.3fmb cache bytes:%I64d = %6.3fmb deepcopy:%I64d each:%8.0fus slot[1]:%d",
					GetCurrentProcessId(),
					m_allocators.size(),
					m_allocated_bytes, m_allocated_bytes*1.0 / 1024 / 1024,
					m_cached_bytes, m_cached_bytes*1.0 / 1024 / 1024,
					m_deepcopy_count,
					m_deepcopy_count == 0 ? 0 : (m_deepcopy_time / m_deepcopy_count),
					m_slots[1].GetCount()
					);
					*/
			}
		}


		//////////////////////////////////////////////////////////////////////////

		void* PageAllocator::AllocMemory(int bytes)
		{
			// 总是取最后一个
			// 如果bytes非常大,超过4kb怎么办?
			// 如果末尾有空余空间怎么办?
			// 挑选一个内存页
			// 默认总是从最后面挑选
			// 当最后一个页面无法分配给定尺寸的内存的时候
			// 看当前所有页面的最大空余空间的页面
			// 空余内容小于给定阀值,就忽略,为了性能
			// 兼顾总内存占用和整体性能
			//double cur = GetHighResTimeD();
			void* ptr = m_current ? m_current->Alloc(bytes) : (m_pagelist ? m_pagelist->Alloc(bytes) : nullptr);
			if (ptr == nullptr)
			{
				if (m_pagelist == nullptr)
					m_pagelist = new MemoryPageList(m_force_free);
				if (m_current)
					m_pagelist->AddPage(m_current);
				m_current = CentralAllocator::Get().AllocPage(bytes);
				BASSERT(m_current && m_current->GetNext() == nullptr && m_current->GetPrev() == nullptr);
				ptr = m_current->Alloc(bytes);
				BASSERT(ptr != nullptr);
			}
			//m_alloc_time += GetHighResTimeD() - cur;
			return ptr;
		}

		PageAllocator::PageAllocator(const RootPtrType vmap, bool inMessage) :m_root(vmap), m_current(nullptr),
			m_central(nullptr), m_inmsg(inMessage), m_alloc_time(0.0), m_pagelist(nullptr),
			m_force_free(true)
		{
			m_central = &CentralAllocator::Get();
		}

		PageAllocator::~PageAllocator()
		{
			//double cur = GetHighResTimeD();
			if (m_current)
			{
				BASSERT(m_current && m_current->GetNext() == nullptr && m_current->GetPrev() == nullptr);
				CentralAllocator::Get().FreePage(m_current,m_force_free);
			}
			m_current = nullptr;
			if (m_pagelist)
			{
				m_pagelist->Release();
				delete m_pagelist;
				m_pagelist = nullptr;
			}
			//double freetime = GetHighResTimeD()-cur;
			//BVIEW("Allocator alloctime:%8dus  freetime:%8dus  count:%8d",
			//	(unsigned int)m_alloc_time, (unsigned int)freetime,ncount);
		}

		PageAllocator* PageAllocator::CreateWithRoot(RootPtrType root, bool inMessage)
		{
			return CentralAllocator::Get().CreateAllocator(root, inMessage);
		}

		void PageAllocator::Destroy(PageAllocator* allocator)
		{
			CentralAllocator::Get().DestroyAllocator(allocator);
		}

		void PageAllocator::SwapRoot(PageAllocator* dest, PageAllocator* source)
		{
			if (dest == nullptr && source == nullptr)
				return;
			const RootPtrType v1 = dest ? dest->GetRoot() : nullptr;
			const RootPtrType v2 = source ? source->GetRoot() : nullptr;
			if (dest)dest->m_root = v2;
			if (source)source->m_root = v1;
		}

		int PageAllocator::GetBytes() const
		{
			int bytes = sizeof(PageAllocator);
			if (m_current)
				bytes += m_current->GetTotalBytes();
			bytes += m_pagelist?m_pagelist->GetBytes():0;
			return bytes;
		}

	}//namespace base;
}//namespace ss;

